package com.skb.web.controller;

import com.skb.core.model.*;
import com.skb.core.model.controller.AccountModel;
import com.skb.core.model.controller.UserModel;
import com.skb.core.service.IAccountService;
import com.skb.core.service.IRoleUserService;
import com.skb.core.service.ISegmentService;
import com.skb.core.service.IUserService;
import com.skb.utils.JsonPagedDataAction;
import com.skb.utils.SysLookup;
import com.skb.web.validator.UserValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.util.*;

@Controller
public class AdminUsersController {

    @Autowired
    private IUserService userService;

    @Autowired
    private IRoleUserService userRoleService;

    @Autowired
    private IAccountService accountService;

    @Autowired
    private ISegmentService segmentService;

    @Autowired
    UserValidator userValidator;

    private String msg;

    private String error;

    private String passwordGenerator(String password) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.encode(password);
    }

    @Transactional(readOnly = true)
    private Map<String,String> segmentMap() {
        Map<String, String> map = new HashMap<>();
        for (Segment segment : segmentService.findAll()) {
            map.put(segment.getId().toString(), segment.getName());
        }
        return map;
    }

    @ModelAttribute("rolesMap")
    public Map<String,String> rolesMap() {
        Map<String,String> rolesMap = new HashMap<>();
        rolesMap.put(SysLookup.ROLE.ROLE_USER.toString(), SysLookup.ROLE.ROLE_USER.getDescription());
        rolesMap.put(SysLookup.ROLE.ROLE_ADMIN.toString(), SysLookup.ROLE.ROLE_ADMIN.getDescription());
        return rolesMap;
    }

    @RequestMapping(value = {"/admin/userList" }, method = RequestMethod.GET)
    public ModelAndView showUsersList() {
        ModelAndView model = new ModelAndView();
        model.setViewName("admin/users");
        return model;
    }

    @Transactional(readOnly = true)
    @RequestMapping(value = "/admin/getUserList", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
    public @ResponseBody JsonPagedDataAction<UserModel> getUsersList(HttpSession session) {
        JsonPagedDataAction<UserModel> data = new JsonPagedDataAction<UserModel>() {};
        List<UserModel> list = new ArrayList<>();

        for (User user : userService.findAll()) {
            UserModel userModel = new UserModel();
            userModel.setLogin(user.getUsername());
            List<String> listTmp = new ArrayList<>();
            for (UserRole userRole : user.getUserRole()) {
                listTmp.add(SysLookup.ROLE.valueOf(userRole.getRole()).getDescription());
            }
            userModel.setRoles(listTmp);
            listTmp = new ArrayList<>();
            for (Account account : user.getUserAccount()) {
                listTmp.add(account.getNumber()+ "</br>");
            }
            userModel.setAccounts(listTmp);
            userModel.setFirstName(user.getFirstName());
            userModel.setLastName(user.getLastName());
            list.add(userModel);
        }
        data.setData(list);
        return data;
    }


    @RequestMapping(value = {"/admin/addUser" }, method = RequestMethod.GET)
    public ModelAndView addUserView() {
        ModelAndView model = new ModelAndView();
        model.addObject("user", new UserModel());
        model.addObject("edit", false);
        model.setViewName("admin/editUser");
        return model;
    }

    @Transactional(readOnly = true)
    @RequestMapping(value = {"/admin/editUser" }, method = RequestMethod.GET)
    public ModelAndView editUserView(@RequestParam(value="username", required=true) String username) {
        ModelAndView model = new ModelAndView();
        User user = userService.findByUserName(username);
        if (username.isEmpty() || user == null) {
            model.addObject("error", "Niepoprawne dane");
            model.setViewName("rediract:/admin/userList");
        }

        UserModel userModel = new UserModel();
        List<String> list = new ArrayList<>();
        for (UserRole role : user.getUserRole()) {
            list.add(role.getRole());
        }
        userModel.setRoles(list);
        userModel.setAddress(user.getAddress());
        userModel.setFirstName(user.getFirstName());
        userModel.setLastName(user.getLastName());
        userModel.setLogin(user.getUsername());
        userModel.setPesel(user.getPesel());

        model.addObject("user", userModel);
        model.addObject("edit", true);
        model.setViewName("admin/editUser");
        return model;
    }

    @Transactional()
    @RequestMapping(value = {"/admin/deleteUser" }, method = RequestMethod.GET)
    public ModelAndView removeUserAction(@RequestParam(value="username", required=true) String username) {
        ModelAndView model = new ModelAndView();
        User user = userService.get(username);
        for (UserRole role : user.getUserRole()) {
            userRoleService.delete(role);
        }
        for (Account account : user.getUserAccount()) {
            accountService.delete(account);
        }
        userService.delete(user);
        model.addObject("msg", "Usunięto użytkownika");
        model.setViewName("redirect:/admin/userList");
        return model;
    }

    @Transactional
    @RequestMapping(value = {"/admin/saveUser" }, method = RequestMethod.POST)
    public ModelAndView addNewUser(@ModelAttribute("edit") Boolean edit, @ModelAttribute("user") UserModel user, BindingResult result, SessionStatus status) {
        ModelAndView model = new ModelAndView();

        if (edit) {
            user.setRePassword("isEdit");
        }
        userValidator.validate(user, result);

        if (result.hasErrors()) {
            model.addObject("user", user);
            model.setViewName("admin/editUser");
            return model;
        }

        if (edit) {
            User u = userService.findByUserName(user.getLogin());
            u.setAddress(user.getAddress());
            u.setFirstName(user.getFirstName());
            u.setLastName(user.getLastName());
            u.setPesel(user.getPesel());
            userService.update(u);

            for (UserRole role : u.getUserRole()) {
                if (!user.getRoles().contains(role.getRole())) {
                    userRoleService.delete(role);
                } else {
                    user.getRoles().remove(role.getRole());
                }
            }
            for (String s : user.getRoles()) {
                userRoleService.create(new UserRole(u, s));
            }

            msg = "Użytkownika zaktualizowano poprawnie";
        } else {

            User newUser = new User(user.getLogin(), passwordGenerator(user.getPassword()), true);
            newUser.setLastName(user.getLastName());
            newUser.setFirstName(user.getFirstName());
            newUser.setPesel(user.getPesel());
            newUser.setAddress(user.getAddress());
            userService.create(newUser);

            for (String role : user.getRoles()) {
                userRoleService.create(new UserRole(newUser, role));
            }

            msg = "Użytkownika dodano poprawnie";
        }
        model.setViewName("redirect:/admin/userList");
        return model;
    }

    @RequestMapping(value = {"/admin/addAccount" }, method = RequestMethod.GET)
    public ModelAndView addAccountView(@RequestParam(value="username", required=true) String username) {
        ModelAndView model = new ModelAndView();
        User user = userService.get(username);

        AccountModel accountModel = new AccountModel();
        accountModel.setUsername(user.getUsername());
        Random random = new Random();
        accountModel.setNumber(String.valueOf(random.nextLong()).replace("-", ""));

        model.addObject("account", accountModel);
        model.addObject("segmentMap", segmentMap());
        model.setViewName("admin/editAccount");
        return model;
    }

    @RequestMapping(value = {"/admin/saveAccount" }, method = RequestMethod.POST)
    public ModelAndView saveAccount(ModelMap model2, @ModelAttribute("account") AccountModel account, BindingResult result, SessionStatus status) {
        ModelAndView model = new ModelAndView();
        User user = userService.get(account.getUsername());
        Segment segment = segmentService.get(Integer.decode(account.getSegment()));

        Account accountToSave = new Account();
        accountToSave.setNumber(account.getNumber());
        accountToSave.setBalance(account.getBalance());
        accountToSave.setSegment(segment);
        accountToSave.setUser(user);

        accountService.create(accountToSave);

        model.addObject("msg", "Konto dodano poprawnie");
        model.setViewName("redirect:/admin/userList");
        return model;
    }




    @RequestMapping(value = {"/admin/workflowRuleList" }, method = RequestMethod.GET)
    public ModelAndView showWorkflowRuleList() {
        ModelAndView model = new ModelAndView();
        model.addObject("msg", msg);
        model.addObject("error", error);
        error = "";
        msg = "";
        model.setViewName("admin/workflowRules");
        return model;
    }



//    @RequestMapping(value = "admin/getWorkflowRuleList", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
//    public @ResponseBody JsonPagedDataAction<WorkflowRule> getWorkflowRuleList(HttpSession session) {
//        JsonPagedDataAction<WorkflowRule> data = new JsonPagedDataAction<WorkflowRule>() {};
//        List<WorkflowRule> list = new ArrayList<>();
//        list = workflowRuleService.findAll();
//        data.setData(list);
//        return data;
//    }

//    @RequestMapping(value = {"/admin/addWfRule" }, method = RequestMethod.GET)
//    public ModelAndView addWorkflowRuleList() {
//        ModelAndView model = new ModelAndView();
//        ModelWorkflowRule rule = new ModelWorkflowRule();
//        rule.setActions(SysListUtils.stringToList("PDF,TRASH,VIEW,EDIT,ARCHIVE"));
//        model.addObject("rule", rule);
//        model.setViewName("admin/editWorkflowRule");
//        return model;
//    }

//    @RequestMapping(value = {"/admin/editWfRule" }, method = RequestMethod.GET)
//    public ModelAndView editWorkflowRuleList(@RequestParam(value="rule", required=true) Integer id) {
//        ModelAndView model = new ModelAndView();
//        ModelWorkflowRule rule = new ModelWorkflowRule();
//        WorkflowRule workflowRule = workflowRuleService.get(id);
//
//        if (workflowRule == null) {
//            error = "Podana reguła nie istnieje.";
//            model.setViewName("redirect:/admin/workflowRuleList");
//            return model;
//        }

//        rule.setRuleId(workflowRule.getRuleId());
//        rule.setDepartment(workflowRule.getDepartment() + ":" + workflowRule.getForm());
//        rule.setForm(workflowRule.getForm());
//        rule.setDestinationDepartment(workflowRule.getDestinationDepartment());
//        rule.setActions(SysListUtils.stringToList(workflowRule.getActions()));
//        rule.setFlows(SysListUtils.stringToList(workflowRule.getFlows()));
//
//        model.addObject("rule", rule);
//        model.setViewName("admin/editWorkflowRule");
//        return model;
//    }

//    @RequestMapping(value = {"/admin/resetWfRule" }, method = RequestMethod.GET)
//    public ModelAndView resetWorkflowRuleList(@RequestParam(value="rule", required=true) Integer id) {
//        ModelAndView model = new ModelAndView();
//        WorkflowRule workflowRule = workflowRuleService.get(id);
//
//        if (workflowRule == null) {
//            error = "Podana reguła nie istnieje.";
//            model.setViewName("redirect:/admin/workflowRuleList");
//            return model;
//        }
//
//        workflowRule.setFlows("");
//        workflowRule.setActions("");
//        workflowRuleService.update(workflowRule);
//
//        msg = "Poprawnie zresetowano regułę.";
//        model.setViewName("redirect:/admin/workflowRuleList");
//        return model;
//    }

//    @RequestMapping(value = {"/admin/deleteWfRule" }, method = RequestMethod.GET)
//    public ModelAndView deleteWorkflowRuleList(@RequestParam(value="rule", required=true) Integer id) {
//        ModelAndView model = new ModelAndView();
//        WorkflowRule workflowRule = workflowRuleService.get(id);
//
//        if (workflowRule == null) {
//            error = "Podana reguła nie istnieje.";
//            model.setViewName("redirect:/admin/workflowRuleList");
//            return model;
//        }
//
//        workflowRuleService.delete(workflowRule);
//
//        msg = "Poprawnie usunięto regułę.";
//        model.setViewName("redirect:/admin/workflowRuleList");
//        return model;
//    }

//    @ModelAttribute("departmentsFlowMap")
//    public Map<String, String> getDepartmentsFlowMap() {
//        Map<String, String> map = new HashMap<>();
//        for (SysLookup.DEPARTMENT d : SysLookup.DEPARTMENT.values()) {
//            map.put(d.toString(), d.getDescription());
//        }
//        map.remove(SysLookup.DEPARTMENT.ARCHIVE.toString());
//        map.remove(SysLookup.DEPARTMENT.TRASH.toString());
//        return map;
//    }
//
//    @ModelAttribute("departmentsMap")
//    public Map<String, String> getDepartmentsMap() {
//        Map<String, String> map = new HashMap<>();
//        for (SysLookup.DEPARTMENT d : SysLookup.DEPARTMENT.values()) {
//            map.put(d.toString(), d.getDescription());
//        }
//        return map;
//    }
//
//    @ModelAttribute("actionsMap")
//    public Map<String, String> getActionsMap(){
//        Map<String, String> map = new HashMap<>();
//        for (SysLookup.ACTION a : SysLookup.ACTION.values()) {
//            map.put(a.toString(),a.getDescription());
//        }
//        return map;
//    }

//    @ModelAttribute("formsMap")
//    public Map<String, String> getFormsMap() {
//        List<Map<String, String>> listForms = orbeonDao.getAllForms();
//        Map<String, String> formMap = new HashMap<>();
//        for (Map<String, String> map : listForms) {
//            formMap.put(map.get(SysLookup.OrbeonColums.DEFINITION_APP) + ":" + map.get(SysLookup.OrbeonColums.DEFINITION_FORM),
//                    SysLookup.DEPARTMENT.valueOf(map.get(SysLookup.OrbeonColums.DEFINITION_APP)).getDescription() + ":" + map.get(SysLookup.OrbeonColums.DEFINITION_FORM));
//        }
//        return formMap;
//    }
//
//    @RequestMapping(value = {"/admin/saveWorkflowRule" }, method = RequestMethod.POST)
//    public ModelAndView saveWorkflowRuleList(@ModelAttribute("rule") ModelWorkflowRule rule) {
//        ModelAndView model = new ModelAndView();
//
//
//        WorkflowRule workflowRule = new WorkflowRule();
//        workflowRule.setRuleId(rule.getRuleId() != null ? rule.getRuleId() : null);
//        workflowRule.setForm(rule.getDepartment().split(":")[1]);
//        workflowRule.setDepartment(rule.getDepartment().split(":")[0]);
//        workflowRule.setDestinationDepartment(rule.getDestinationDepartment());
//        workflowRule.setActions(SysListUtils.listToString(rule.getActions()));
//        workflowRule.setFlows(SysListUtils.listToString(rule.getFlows()));
//        try {
//            if (workflowRule.getRuleId() != null) {
//                workflowRuleService.update(workflowRule);
//                msg  ="Poprawnie zaktualizowano regułę workflow";
//            } else {
//                workflowRuleService.create(workflowRule);
//                msg = "Poprawnie dodano regułę workflow";
//            }
//        } catch (ConstraintViolationException e) {
//            model.addObject("error", "Taka reguła już istnieje.");
//            model.addObject("rule", rule);
//            model.setViewName("admin/editWorkflowRule");
//            return  model;
//        }
//
//        model.setViewName("redirect:/admin/workflowRuleList");
//        return model;
//    }
}
